home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / visulztn / saoimage / saoimage.lha / rgndrop.c < prev    next >
C/C++ Source or Header  |  1990-04-20  |  6KB  |  204 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    rgndrop.c (Region Drop)
  6.  * Purpose:    Select and remove a region no longer wanted
  7.  * Subroutine:    unsave_region()            returns: void
  8.  * Subroutine:    region_indicated_by_pointer()    returns: struct cursorRec *
  9.  * Copyright:    1989 Smithsonian Astrophysical Observatory
  10.  *        You may do anything you like with this file except remove
  11.  *        this copyright.  The Smithsonian Astrophysical Observatory
  12.  *        makes no representations about the suitability of this
  13.  *        software for any purpose.  It is provided "as is" without
  14.  *        express or implied warranty.
  15.  * Modified:    {0} Michael VanHilst    initial version        27 June 1989
  16.  *        {n} <who> -- <does what> -- <when>
  17.  */
  18.  
  19. #include <stdio.h>        /* stderr, NULL, etc. */
  20. #include <math.h>        /* declare sqrt */
  21. #include <X11/Xlib.h>        /* X window stuff */
  22. #include <X11/Xutil.h>        /* X window manager stuff */
  23. #include "hfiles/constant.h"    /* define codes */
  24. #include "hfiles/color.h"    /* cursor colors needed by Cursor.h */
  25. #include "hfiles/cursor.h"    /* define cursor parameter structures */
  26. #include "hfiles/define.h"    /* define SQR, SMALL_NUMBER */
  27.  
  28. extern struct cursorRec *cycle_region;
  29.  
  30. /*
  31.  * Subroutine:    unsave_region
  32.  * Purpose:    Remove and discard region from region list
  33.  */
  34. void unsave_region ( cursor, dead_meat )
  35.      struct cursorRec *cursor;        /* i: main cursor record */
  36.      struct cursorRec *dead_meat;    /* i: ptr to region being deleted */
  37. {
  38.   struct cursorRec *region;
  39.   void free_cursor();
  40.  
  41.   if( (cursor->next_region == NULL) || (dead_meat == NULL) )
  42.     return;
  43.   region = cursor;
  44.   while( region->next_region != dead_meat ) {
  45.     region = region->next_region;
  46.     region->index--;
  47.   }
  48.   region->next_region = dead_meat->next_region;
  49.   /* if deleting region pointed at by cycle region, change cycle region */
  50.   if( cycle_region == dead_meat )
  51.     cycle_region = region;
  52.   /* free deleted region and any annuli it might have */
  53.   do {
  54.     region = dead_meat->next_annulus;
  55.     free_cursor (dead_meat);
  56.     dead_meat = region;
  57.   } while( dead_meat != NULL );
  58. }
  59.  
  60. /*
  61.  * Subroutine:    region_indicated_by_pointer
  62.  * Purpose:    Identify which region if any is indicated by the pointer
  63.  * Method:    Chooses smallest region which encloses pointer.  (Point
  64.  *        cursors enclose one or two digit label but have 0 area).
  65.  *        In case of equal areas (i.e. points), closer center is used.
  66.  */
  67. struct cursorRec *region_indicated_by_pointer ( cursor, x, y, point_only )
  68.      struct cursorRec *cursor;
  69.      int x, y;
  70.      int point_only;
  71. {
  72.   struct cursorRec *region, *chosen;
  73.   static int pointer_is_inside_region();
  74.   static int closer_to_center();
  75.  
  76.   chosen = NULL;
  77.   region = cursor->next_region;
  78.   /* erase smallest region which encloses the mouse */
  79.   while( region != NULL ) {
  80.     if( !point_only || region->type == COP_Point ) {
  81.       if( pointer_is_inside_region(x, y, region) ) {
  82.     if( (chosen == NULL) || (region->file.area < chosen->file.area) ) {
  83.       chosen = region;
  84.     } else if( (region->file.area == chosen->file.area) &&
  85.            closer_to_center(region, chosen, x, y) )
  86.       /* compare distance from center */
  87.       chosen = region;
  88.       }
  89.     }
  90.     region = region->next_region;
  91.   }
  92.   return( chosen );
  93. }
  94.  
  95. /*
  96.  * Subroutine:    closer_to_center
  97.  */
  98. static int closer_to_center ( challenger, champ, x, y )
  99.      struct cursorRec *challenger, *champ;
  100.      int x, y;
  101. {
  102.   double X, Y, Xn, Yn;
  103.  
  104.   X = (double)x + 0.5 - champ->win.X;
  105.   Y = (double)y + 0.5 - champ->win.Y;
  106.   Xn = (double)x + 0.5 - challenger->win.X;
  107.   Yn = (double)y + 0.5 - challenger->win.Y;
  108.   if( (SQR(Xn) + SQR(Yn)) > (SQR(X) + SQR(Y)) )
  109.     return( 1 );
  110.   else
  111.     return( 0 );
  112. }
  113.  
  114. /*
  115.  * Subroutine:    is_inside_region
  116.  * Purpose:    Determine if mouse is within a region
  117.  */
  118. static int pointer_is_inside_region ( x, y, region )
  119.      int x, y;
  120.      struct cursorRec *region;
  121. {
  122.   double rayX, rayY, ray;
  123.   int inside;
  124.   static int pointer_is_inside_polygon();
  125.  
  126.   if( region->type == COP_Polygon )
  127.     return( pointer_is_inside_polygon((double)x, (double)y,
  128.                       region->poly, region->poly_cnt) );
  129.   rayX = (double)x + 0.5 - region->win.X;
  130.   rayY = (double)y + 0.5 - region->win.Y;
  131.   inside = 0;
  132.   switch( region->type ) {
  133.   case COP_Circle:
  134.     if( (SQR(rayX) + SQR(rayY)) <
  135.         (region->win.rayX * region->win.rayY) )
  136.       inside = 1;
  137.     break;
  138.   case COP_Box:
  139.     if( region->rot.angle != 0.0 ) {
  140.       /* rotate mouse coords into the rotated space */
  141.       ray = (rayX * region->rot.cos) + (rayY * region->rot.sin);
  142.       rayY = (rayY * region->rot.cos) - (rayX * region->rot.sin);
  143.       rayX = ray;
  144.     }
  145.     if( (rayX < region->win.rayX) && (rayX > -region->win.rayX) &&
  146.         (rayY < region->win.rayY) && (rayY > -region->win.rayY) )
  147.       inside = 1;
  148.     break;
  149.   case COP_Point:
  150.     /* cursor is over point index marker (one or two 6x13 characters) */
  151.     if( (rayX >= -2) && (rayX <= 6) && (rayY <= 2) && (rayY >= (-11)) )
  152.       inside = 1;
  153.     break;
  154.   case COP_Ellipse:
  155.     rayX *= region->ctrl.axis_ratio;
  156.     ray = sqrt(SQR(rayX) + SQR(rayY));
  157.     if( (ray < region->win.rayY) &&
  158.         ((ray / region->ctrl.axis_ratio) < region->win.rayX) )
  159.       inside = 1;
  160.     break;
  161.   default:
  162.     break;
  163.   }
  164.   return( inside );
  165. }
  166.  
  167. /*
  168.  * Subroutine:    pointer_is_inside_polygon
  169.  * Purpose:    Determine if mouse is within a polygon
  170.  */
  171. static int pointer_is_inside_polygon ( x, y, polypt, poly_cnt )
  172.      double x, y;
  173.      PolyPoint *polypt;
  174.      int poly_cnt;
  175. {
  176.   double yi, yj, xi, xj;
  177.   int i, j, crossings;
  178.  
  179.   crossings = 0;
  180.   j = poly_cnt - 1;
  181.   for( i=0; i<poly_cnt; i++ ) {
  182.     if( (polypt[i].winX >= x) != (polypt[j].winX > x) ) {
  183.       yi = polypt[i].winY;
  184.       yj = polypt[j].winY;
  185.       if( (yi < y) || (yj < y) ) {
  186.     if( (yi < y) && (yj < y) )
  187.       crossings++;
  188.     else {
  189.       xi = polypt[i].winX;
  190.       xj = polypt[j].winX;
  191.       if( xj != xi ) {
  192.         if( ((x - xj) * (yi-yj)/(xi-xj) + yj) < y )
  193.           crossings++;
  194.       }
  195.     }
  196.       }
  197.     }
  198.   }
  199.   if( crossings & 1 )
  200.     return(1);
  201.   else
  202.     return(0);
  203. }
  204.